<?php
/**
 * @author Anna Khabibullina
 * @since 2012-02-27
 */
class Zgm_Acl extends Zend_Acl {

   public function __construct($aclConfigPath) {
      // If file with path $aclConfigPath exists and it is not empty process it.
      if ((file_exists($aclConfigPath)) AND ('' !== file_get_contents($aclConfigPath))) {
         $aclConfigObject = new Zend_Config_Ini($aclConfigPath, APPLICATION_ENV);
         $aclConfigArray = $aclConfigObject->toArray();
         // Add roles.
         if (isset($aclConfigArray['roles']) AND (!empty($aclConfigArray['roles']))) {
            $roles = $aclConfigArray['roles'];
            $this->_addRoles($roles);
            // Add resources.
            if (isset($aclConfigArray['resources']) AND (!empty($aclConfigArray['resources']))) {
               $resources = $aclConfigArray['resources'];
               ksort($resources);
               $this->_addResources($resources);
               // Add "deny" rules.
               if (isset($aclConfigArray['deny']) AND (!empty($aclConfigArray['deny']))) {
                  $denials = $aclConfigArray['deny'];
                  foreach ($denials as $role => $deny) {
                     $this->_addRules($role, $deny, false);
                  }
               }
               // Add "allow" rules.
               if (isset($aclConfigArray['allow']) AND (!empty($aclConfigArray['allow']))) {
                  $allowances = $aclConfigArray['allow'];
                  foreach ($allowances as $role => $rule) {
                     $this->_addRules($role, $rule);
                  }
               }
            } else {
               syslog(LOG_INFO, 'No resources available found in configuration file '.
                                $aclConfigPath);
            }
         } else {
            syslog(LOG_INFO, "No roles available found in configuration file $aclConfigPath.");
         }
      } else {
         syslog(LOG_INFO, "Configuration file $aclConfigPath doesn't exists or empty.");
      }
   }

   /**
    * Adds roles listed in config file.
    * @param array $roles Array of roles having a role name as key and its parent as value.
    */
   protected function _addRoles($roles) {
      foreach ($roles as $role => $parent) {
         if (!$this->hasRole($role)) {
            $parent = (empty($parent)) ? null : explode(',', (string)$parent);
            $this->addRole(new Zend_Acl_Role($role), $parent);
         }
      }
   }

   /**
    * Adds resources listed in config file.
    * @param array $resources Array of resources having a resource name as key and
    * its parent as value.
    */
   protected function _addResources($resources) {
      foreach ($resources as $resource => $parent) {
         $parent = (empty($parent)) ? null : explode(',', (string)$parent);
         $this->add(new Zend_Acl_Resource($resource), $parent);
      }
   }

   /*
    * Adds an "allow" or "deny" rule listed in config file to the ACL
    * respectively to argument $isAllow given.
    * @param string $role
    * @param array $rule Array having resource name as key and array of priveleges as value.
    * @param boolean $isAllow
    */
   protected function _addRules($role, $rules, $isAllow = true) {
      $role = ($role == 'all') ? null: (string)$role;
      if (count($rules) > 0) {
         foreach($rules as $resource => $privileges) {
            $resource = ($resource == 'all') ? null: (string)$resource;
            $privileges = $privileges['priveleges'];
            if (!empty($privileges)) {
               $privileges = explode(',', $privileges);
            } else {
               $privileges = null;
            }
            // Add the appropriate rule.
            if ($isAllow) {
               $this->allow($role, $resource, $privileges);
            } else {
               $this->deny($role, $resource, $privileges);
            }
         }
      }
   }
}
